#pragma once
#include <iostream>
#include <string>
#include <sstream>
#include<cstring>
#include<memory>
#include <fstream>
#include<filesystem>
#include<unistd.h>
#include <time.h>
#include"Thread.hpp"
const std::string default_log_path = "/home/dyx/gitee/linux/IO_Mode/Epoll/log/";
const std::string default_log_name = "log.txt";

enum class log_level {//日志等级
    DEBUG = 1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};
std::string CurrentTime()//获取当前时间
{
    time_t time_stamp = time(nullptr);
    struct tm curr;
    localtime_r(&time_stamp, &curr);
    char time_buffer[1024];
    snprintf(time_buffer,sizeof(time_buffer),"%4d-%02d-%02d %02d:%02d:%02d",
        curr.tm_year+1900,
        curr.tm_mon+1,
        curr.tm_mday,
        curr.tm_hour,
        curr.tm_min,
        curr.tm_sec);
    return std::string(time_buffer);
}
std::string GetLogLevelString(log_level level)//获取日志等级字符串
{
    switch(level){
        case log_level::DEBUG:
            return "DEBUG";
        case log_level::INFO:
            return "INFO";
        case log_level::WARNING:
            return "WARNING";
        case log_level::ERROR:
            return "ERROR";
        case log_level::FATAL:
            return "FATAL";
        default:
            return "UNKNOWN";
    }
}

class LogStrategy{//日志策略接口(刷新)
    public:
        virtual ~LogStrategy() = default;
        virtual void SyncLog(const std::string& log) = 0;
};

class ConsoleLogStrategy : public LogStrategy{//控制台日志策略
    public:
        void SyncLog(const std::string& message) override
        {
            My_thread::LockGuard lock(_lock);
            std::cout << message << std::endl;
        }
    private:
        My_thread::Mutex _lock;
};

class FileLogStrategy : public LogStrategy{//文件日志策略
    public:
        FileLogStrategy(const std::string& logpath = default_log_path, const std::string& logname = default_log_name) 
            :_logpath(logpath), _logname(logname)
        {
            My_thread::LockGuard lock(_lock);
            if(std::filesystem::exists(_logpath))
                return;
            try{
                std::filesystem::create_directories(_logpath);
            }            
            catch(const std::filesystem::filesystem_error& e){
                std::cerr<<e.what()<<std::endl;
            }
        }
        void SyncLog(const std::string& message) override
        {
            My_thread::LockGuard lock(_lock);
            std::string log = _logpath + _logname;
            std::ofstream out(log, std::ios::app);//日志写入追加
            if(!out.is_open()){
                return;
            }
            out<<message<<std::endl;
            out.close();
        }
    private:
        std::string _logpath;
        std::string _logname;
        My_thread::Mutex _lock;
};

class Log{//日志类:构造日志字符串，根据策略刷新日志
    public:
        Log()
        {
            _strategy = std::make_shared<ConsoleLogStrategy>();//默认策略为控制台日志策略
        }
        void EnableConsoleLog()
        {
            _strategy = std::make_shared<ConsoleLogStrategy>();//控制台日志策略 
        }
        void EnableFileLog(const std::string& logpath = default_log_path, const std::string& logname = default_log_name)
        {
            _strategy = std::make_shared<FileLogStrategy>(logpath, logname);//文件日志策略
        }
        ~Log()
        {

        }
        class LogMessage{//日志消息类
            public:
                LogMessage(log_level level, const std::string& filename, int line,Log& logger)
                    :_currtime(CurrentTime()), 
                    _level(level), 
                    _pid(getpid()), 
                    _filename(filename), 
                    _line(line),
                    _logger(logger)
                {
                    std::stringstream ssbuffer;//字符串流
                    ssbuffer<<"["<<_currtime<<"]"
                    <<"["<<GetLogLevelString(_level)<<"]"
                    <<"["<<_pid<<"]"
                    <<"["<<_filename<<":"<<_line<<"] - ";
                    _loginfo = ssbuffer.str();
                }
                template<typename T>
                LogMessage& operator<<(const T& info)
                {
                    std::stringstream ssbuffer;
                    ssbuffer<<info;
                    _loginfo += ssbuffer.str();
                    return *this;//返回自身
                }
                ~LogMessage()
                {
                    if(_logger._strategy){
                        _logger._strategy->SyncLog(_loginfo);//刷新日志
                    }
                }
            private:
                std::string _currtime;//当前日志时间
                log_level _level;//日志等级
                pid_t _pid;//进程id
                std::string _filename;//源文件名称
                int _line;//源文件行号
                std::string _loginfo;//一条完整的日志信息
                Log& _logger;//根据不同的日志策略进行刷新
        };   
        LogMessage operator()(log_level level, const std::string& filename, int line)
        {
            return LogMessage(level, filename, line,*this);
        }
    private:
       std::shared_ptr<LogStrategy> _strategy;//日志策略

};
Log logger;
#define LOG(level) logger(level, __FILE__, __LINE__)//__FILE__为源文件名，__LINE__为源文件行号
#define ENABLE_CONSOLE_LOG() logger.EnableConsoleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()